#include <zmq.h>
#include <stdio.h>
#include <string.h>
#include "pciemsg.h"

//#define COMM_URL "tcp://127.0.0.1:5555"
#define COMM_URL "inproc://lat_test"

void dump_msg(const void* data, int size)
{
    unsigned char* ptr = (unsigned char*)data;
    printf("[%03d] ", size);
    int i = 0;
    for (i = 0; i < size; i++)
        printf("%02X", ptr[i]);
    //printf("%.*s\r\n", size, ptr);
}

void dump_addressX(const char* header, const void* data, int size)
{
    unsigned char* ptr = (unsigned char*)data;
    printf("[%s %03d] ", header, size);
    int i = 0;
    for (i = 0; i < size; i++)
        printf("%02X", ptr[i]);

    printf("\n");
}

int fa_pcie_get_reg(void* fd, fa_pcie_req_arr_t *req, fa_pcie_rep_arr_t *rep)
{
    char buf[2048] = {0};
    //dump_addressX("send", (const void *)&req, sizeof(fa_pcie_req_t));
    int len = zmq_send(fd, (void*)req, sizeof(fa_pcie_req_t), 0);
    //here can transfer rep to reduce mem copy
    int ret = zmq_recv(fd, buf, sizeof(buf), 0);
    if (ret > 0) 
    {
        *rep = *(fa_pcie_rep_arr_t*)buf;
        //printf("result is %d\r\n", rep->rep[0].value[0]);
    }
    return len;
}

void fa_pcie_recv_request(void* fd)
{
    zmq_msg_t address;
    zmq_msg_t data;
    int ret;

    zmq_msg_init(&address);
    zmq_msg_init(&data);
    /*接收到的第一帧表示对端的地址*/
    void* watch1;
    watch1 = zmq_stopwatch_start();

    ret = zmq_msg_recv(&address, fd, 0);
    //dump_address(zmq_msg_data(&address), ret);
    unsigned long usconsume = zmq_stopwatch_stop(watch1);
    //printf("recv time consumed %ld\r\n", usconsume);
    if (ret < 0) {
        return;
    }

    /*从第二帧开始才是对端发来的消息*/
    if (zmq_msg_more(&address))
    {
        ret = zmq_msg_recv(&data, fd, 0);
    }

    //printf("ret = %d...\r\n", ret);
    if (ret > 0)
    {
        fa_pcie_handle_msg(fd, &address, zmq_msg_data(&data), ret);
    }

    zmq_msg_close(&address);
    zmq_msg_close(&data);
}

int fa_pcie_set_regs(void* fd, fa_pcie_req_arr_t* req, fa_pcie_rep_arr_t* rep)
{
    uint32_t size = fa_pcie_count_req_mem(req->reqnum);
    //use zmq_send_const to avoid memory reallocating
    int len = zmq_send_const(fd, req, size, 0);
    //if need to get result
    if (rep)
    {

    }
    return len;
}

int fa_pcie_sample_value(void* fd, uint32_t *value)
{
    int len;

    fa_pcie_req_arr_t req = {0};
    fa_pcie_rep_arr_t rep = {0};
    
    req.reqnum = 1;
    req.req[0].op = FA_PCIE_GET;
    req.req[0].count = 48;
    len = fa_pcie_get_reg(fd, &req, &rep);
    return len;
}

void dump_address(const void* data, int size)
{
    unsigned char* ptr = (unsigned char*)data;
    printf("[%03d] ", size);
    int i = 0;
    //for (i = 0; i < size; i++)
    //    printf("%02X", ptr[i]);
    
    printf("%.*s\r\n", size, ptr);
    printf("\n");
}

void* watch;

void dealer_main(void* arg)
{
    void* context = arg;
    void* dealer = zmq_socket(context, ZMQ_DEALER);

    fa_pcie_req_arr_t* arr = fa_pcie_apply_req_mem(FA_PCIE_REQ_ARR_SIZE);

    zmq_setsockopt(dealer, ZMQ_ROUTING_ID, "S100", 4);
    zmq_connect(dealer, COMM_URL);

    int ret;
    char buf[256] = "hello";
    int total = 10;

    watch = zmq_stopwatch_start();
    while (total)
    {
        arr->reqnum = 0;
        //strcpy(buf, "hello");
        /*发送一帧，不需要发送地址帧*/
        fa_pcie_set_reg2(arr, 1,    0x11);
        fa_pcie_set_reg2(arr, 2,    0x22);
        fa_pcie_set_reg2(arr, 3,    0x33);
        fa_pcie_set_reg2(arr, 5,    0x44);
        fa_pcie_set_reg2(arr, 6,    0x55);
        fa_pcie_set_reg2(arr, 7,    0x66);
        fa_pcie_set_reg2(arr, 8,    0x77);
        fa_pcie_set_reg2(arr, 9,    0x88);
        fa_pcie_set_reg2(arr, 10,   0x99);
        fa_pcie_set_reg2(arr, 11,   0xAA);
        fa_pcie_set_reg2(arr, 1,    0x11);
        fa_pcie_set_reg2(arr, 2,    0x22);
        fa_pcie_set_reg2(arr, 3,    0x33);
        fa_pcie_set_reg2(arr, 5,    0x44);
        fa_pcie_set_reg2(arr, 6,    0x55);
        fa_pcie_set_reg2(arr, 7,    0x66);
        fa_pcie_set_reg2(arr, 8,    0x77);
        fa_pcie_set_reg2(arr, 9,    0x88);
        fa_pcie_set_reg2(arr, 10,   0x99);
        fa_pcie_set_reg2(arr, 11,   0xAA);

        //uint32_t size = sizeof(fa_pcie_req_arr_t) + FA_PCIE_REQ_ARR_SIZE * sizeof(fa_pcie_req_t);
        //zmq_send_const(dealer, arr, size, 0);
        fa_pcie_set_regs(dealer, arr, NULL);

        void* watch1;
        watch1 = zmq_stopwatch_start();
        uint32_t value = 0;
        fa_pcie_sample_value(dealer, &value);
        unsigned long usconsume = zmq_stopwatch_stop(watch1);
        printf("Get time consumed %ld\r\n", usconsume);

        total--;
    }

    zmq_sleep(1);
    zmq_close(dealer);
    zmq_ctx_destroy(context);
}

int main(void)
{
    void* context = zmq_ctx_new();
    void* router = zmq_socket(context, ZMQ_ROUTER);
    zmq_bind(router, COMM_URL);

    zmq_threadstart(dealer_main, context);

    while (1)
    {
        fa_pcie_recv_request(router);
        //unsigned long usconsume = zmq_stopwatch_stop(watch);
        //printf("time consumed %ld\r\n", usconsume);
        //watch = zmq_stopwatch_start();

        //fa_pcie_recv_msg(router);
    }
    zmq_close(router);
    zmq_ctx_destroy(context);
    return 0;
}